﻿using System;
using System.Buffers.Text;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace MyUtils.Core
{
    /// <summary>
    /// AES加密类
    /// </summary>
    public class AES
    {
        private static byte[] _aesKetByte = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
        private static string _aesKeyStr = Encoding.UTF8.GetString(_aesKetByte);

        /// <summary>
        /// 生成随机密钥
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        public static byte[] GetIv(int n)
        {
            char[] arrChar = new char[]
            {
                'a','b','d','c','e','f','g','h','i','j','k','l','m','n','p','r','q','s','t','u','v','w','z','y','x',
                '0','1','2','3','4','5','6','7','8','9',
                'A','B','C','D','E','F','G','H','I','J','K','L','M','N','Q','P','R','T','S','V','U','W','X','Y','Z'
            };

            StringBuilder num = new StringBuilder();
            Random rnd = new Random(DateTime.Now.Millisecond);
            for (int i = 0; i < n; i++)
                num.Append(arrChar[rnd.Next(0, arrChar.Length)].ToString());

            _aesKetByte = Encoding.UTF8.GetBytes(num.ToString());
            return _aesKetByte;
        }

        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="Data">被加密的明文</param>
        /// <param name="Key">密钥</param>
        /// <param name="Vector">向量</param>
        /// <returns>密文</returns>
        public static String AESEncrypt(String Data, String Key, String Vector)
        {
            Byte[] plainBytes = Encoding.UTF8.GetBytes(Data);
            Byte[] bKey = new Byte[32];
            Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
            Byte[] bVector = new Byte[16];
            Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);
            Byte[] Cryptograph = null; // 加密后的密文
            Rijndael Aes = Rijndael.Create();
            try
            {
                // 开辟一块内存流
                using (MemoryStream Memory = new MemoryStream())
                {
                    // 把内存流对象包装成加密流对象
                    using (CryptoStream Encryptor = new CryptoStream(Memory,
                    Aes.CreateEncryptor(bKey, bVector),
                    CryptoStreamMode.Write))
                    {
                        // 明文数据写入加密流
                        Encryptor.Write(plainBytes, 0, plainBytes.Length);
                        Encryptor.FlushFinalBlock();
                        Cryptograph = Memory.ToArray();
                    }
                }
            }
            catch
            {
                Cryptograph = null;
            }

            return Convert.ToBase64String(Cryptograph);
        }


        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="Data">被解密的密文</param>
        /// <param name="Key">密钥</param>
        /// <param name="Vector">向量</param>
        /// <returns>明文</returns>
        public static String AESDecrypt(String Data, String Key, String Vector)
        {
            Byte[] encryptedBytes = Convert.FromBase64String(Data);
            Byte[] bKey = new Byte[32];
            Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
            Byte[] bVector = new Byte[16];
            Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);
            Byte[] original = null; // 解密后的明文
            Rijndael Aes = Rijndael.Create();
            try
            {
                // 开辟一块内存流，存储密文
                using (MemoryStream Memory = new MemoryStream(encryptedBytes))
                {
                    // 把内存流对象包装成加密流对象
                    using (CryptoStream Decryptor = new CryptoStream(Memory,
                    Aes.CreateDecryptor(bKey, bVector),
                    CryptoStreamMode.Read))
                    {
                        // 明文存储区
                        using (MemoryStream originalMemory = new MemoryStream())
                        {
                            Byte[] Buffer = new Byte[1024];
                            Int32 readBytes = 0;
                            while ((readBytes = Decryptor.Read(Buffer, 0, Buffer.Length)) > 0)
                                originalMemory.Write(Buffer, 0, readBytes);

                            original = originalMemory.ToArray();
                        }
                    }
                }
            }
            catch
            {
                original = null;
            }
            return Encoding.UTF8.GetString(original);
        }

        // <summary>
        /// AES加密(无向量)
        /// </summary>
        /// <param name="Data">被加密的明文</param>
        /// <param name="Key">密钥</param>
        /// <returns>密文</returns>
        public static string AESEncrypt(String Data, String Key)
        {
            return AESEncrypt(Data, Key, _aesKeyStr);
        }

        /// <summary>
        /// AES解密(无向量)
        /// </summary>
        /// <param name="Data">被加密的明文</param>
        /// <param name="Key">密钥</param>
        /// <returns>明文</returns>
        public static string AESDecrypt(String Data, String Key)
        {
            return AESDecrypt(Data, Key, _aesKeyStr);
        }
    }


    /// <summary>
    /// base64编码类
    /// </summary>
    public class Base64
    {
        const string _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

        /// <summary>
        /// 编码
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        public static string Encode(string e)
        {
            int t, n, o, i, a, r, s;
            string c = "";
            int u = 0;

            e = _utf8Encode(e);

            while (u < e.Length)
            {
                t = (int)e[u++];
                n = u < e.Length ? (int)e[u++] : 0;
                o = u < e.Length ? (int)e[u++] : 0;
                i = t >> 2;
                a = ((t & 3) << 4) | (n >> 4);
                r = ((n & 15) << 2) | (o >> 6);
                s = o & 63;

                if (double.IsNaN(n))
                {
                    r = s = 64;
                }
                else if (double.IsNaN(o))
                {
                    s = 64;
                }

                c += _keyStr[i].ToString() + _keyStr[a].ToString() + _keyStr[r].ToString() + _keyStr[s].ToString();
            }

            return c;
        }
        /// <summary>
        /// 解码
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        public static string Decode(string e)
        {
            int t, n, o, i, a, r, s;
            string c = "";
            int u = 0;

            e = Regex.Replace(e, "[^A-Za-z0-9\\+\\/\\=]", "");
            while (u < e.Length)
            {
                i = _keyStr.IndexOf(e[u++]);
                a = _keyStr.IndexOf(e[u++]);
                r = _keyStr.IndexOf(e[u++]);
                s = _keyStr.IndexOf(e[u++]);

                t = (i << 2) | (a >> 4);
                n = ((a & 15) << 4) | (r >> 2);
                o = ((r & 3) << 6) | s;

                c += ((char)t).ToString();
                if (r != 64)
                {
                    c += ((char)n).ToString();
                }
                if (s != 64)
                {
                    c += ((char)o).ToString();
                }
            }

            c = _utf8Decode(c);
            return c;
        }


        private static string _utf8Encode(string e)
        {
            e = e.Replace("\r\n", "\n");
            StringBuilder t = new StringBuilder();
            for (int n = 0; n < e.Length; n++)
            {
                int o = e[n];
                if (o < 128)
                {
                    t.Append((char)o);
                }
                else if (o > 127 && o < 2048)
                {
                    t.Append((char)((o >> 6) | 192));
                    t.Append((char)((o & 63) | 128));
                }
                else
                {
                    t.Append((char)((o >> 12) | 224));
                    t.Append((char)(((o >> 6) & 63) | 128));
                    t.Append((char)((o & 63) | 128));
                }
            }
            return t.ToString();
        }

        private static string _utf8Decode(string e)
        {
            StringBuilder t = new StringBuilder();
            int n = 0, o, c1, c2;
            while (n < e.Length)
            {
                o = (int)e[n];
                if (o < 128)
                {
                    t.Append((char)o);
                    n++;
                }
                else if (o > 191 && o < 224)
                {
                    c2 = (int)e[n + 1];
                    t.Append((char)((o & 31) << 6 | (c2 & 63)));
                    n += 2;
                }
                else
                {
                    c2 = (int)e[n + 1];
                    c1 = (int)e[n + 2];
                    t.Append((char)((o & 15) << 12 | (c2 & 63) << 6 | (c1 & 63)));
                    n += 3;
                }
            }
            return t.ToString();
        }
    }



    /// <summary>
    /// 快速Token加密解密
    /// </summary>
    public class Token
    {
        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="inputs">数据数组</param>
        /// <param name="key">密钥</param>
        /// <param name="spiltChar">数据数组分割符</param>
        /// <returns></returns>
        public static string Encode(string[] inputs,string key,char spiltChar = ',')
        {
            string middles = $"{Guid.NewGuid()}{spiltChar}";
            for (int i = 0; i < inputs.Length; i++)
            {
                var middle = Base64.Encode(inputs[i]);

                middles += middle;
                if (i < inputs.Length - 1)
                    middles += spiltChar;
            }
            var base64Str = Base64.Encode(middles);
            return AES.AESEncrypt(base64Str, key);
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="inputs">数据数组</param>
        /// <param name="key">密钥</param>
        /// <param name="spiltChar">数据数组分割符</param>
        /// <returns></returns>
        public static string[] Decode(string input,string key,char spiltChar = ',')
        {
            var aesRet = AES.AESDecrypt(input, key);
            var output = new List<string>();
            var middle = Base64.Decode(aesRet);
            var tmp = middle.Split(',');
            for (int i = 0; i < tmp.Length; i++)
            {
                if (i != 0)
                {
                    var ret = Base64.Decode(tmp[i]);
                    ret = Regex.Replace(ret, @"\0+", "");
                    output.Add(ret);
                }
            }
            return output.ToArray();
        }
    }
}
